package com.educate.common.mongo;

import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.stereotype.Component;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author ycs
 * @qq 897710401
 * 自动清除不是PO对象中的参数
 */
@Component
public class MongoConvertEvent implements ApplicationListener<BeforeConvertEvent> {

    @Override
    public void onApplicationEvent(BeforeConvertEvent beforeConvertEvent) {
        Object source = beforeConvertEvent.getSource();
        Class<?> poClass = source.getClass();
        while (poClass.getName().endsWith("VO") || poClass.getName().endsWith("BO")) {
            Class<?> superclass = poClass.getSuperclass();
            if (superclass == null) break;
            poClass = superclass;
        }
        removeNonParameterVo(source, poClass);
    }

    /**
     * 清除不是PO中的参数
     *
     * @param source
     * @param poCass
     */
    private void removeNonParameterVo(Object source, Class poCass) {
        if (source.getClass() == poCass) return;
        PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(source.getClass());
        BeanUtils.getPropertyDescriptors(poCass);
        for (PropertyDescriptor descriptor : descriptors) {
            Method readMethod = descriptor.getReadMethod();
            Method writeMethod = descriptor.getWriteMethod();
            if (readMethod == null || writeMethod == null) continue;
            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                readMethod.setAccessible(true);
            }
            PropertyDescriptor voPd = BeanUtils.getPropertyDescriptor(poCass, descriptor.getName());
            if (voPd != null) continue;
            Object value = null;
            try {
                value = readMethod.invoke(source);
            } catch (Throwable e) {
                e.printStackTrace();
            }
            if (value == null) continue;
            Method poWriteMethod = descriptor.getWriteMethod();
            if (poWriteMethod == null) continue;
            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                writeMethod.setAccessible(true);
            }
            try {
                writeMethod.invoke(source, new Object[]{null});
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
}
